package org.hzero.business.report.builder.impl;

import org.hzero.business.report.annoations.KnifeReportHeaderColumnAnnotation;
import org.hzero.business.report.annoations.KnifeReportLineColumnAnnotation;
import org.hzero.business.report.builder.KnifeReportColumnsBuilder;
import org.hzero.business.report.dto.KnifeReportColumnOrder;
import org.hzero.business.report.dto.KnifeReportHeaderColumn;
import org.hzero.business.report.dto.KnifeReportLineColumn;
import org.hzero.business.report.enums.ColumnOrderEnum;
import org.hzero.interfaces.common.utils.KnifeReflectUtil;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 默认构造方式
 *
 * @author: tianhao.luo@hand-china.com 2021/2/19  16:19
 */
public class DefaultKnifeReportColumnsBuilder<Header, Line> implements KnifeReportColumnsBuilder{

    /**
     * 时间类型
     */
    public static final String DATE_TYPE = "date";

    /**
     * 存放报表头
     */
    private final Class<Header> headerClass;
    /**
     * 存放报表行
     */
    private final Class<Line> lineClass;

    public DefaultKnifeReportColumnsBuilder(Class<Header> headerClass, Class<Line> lineClass) {
        this.headerClass = headerClass;
        this.lineClass = lineClass;
    }


    @Override
    public List<KnifeReportHeaderColumn> buildHeaderColumns(ColumnOrderEnum columnOrderEnum) {
        KnifeReportColumnOrder[] orderColumns = columnOrderEnum.getOrderColumns();
        List<Field> fieldList = KnifeReflectUtil.getAllFieldRecursionWithAnnotation(headerClass, KnifeReportHeaderColumnAnnotation.class);
        // 转化为Map
        Map<String, KnifeReportHeaderColumnAnnotation> map = new HashMap<>(fieldList.size());
        fieldList.forEach(field -> {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            map.put(field.getName(), field.getAnnotation(KnifeReportHeaderColumnAnnotation.class));
        });

        List<KnifeReportHeaderColumn> knifeReportHeaderColumns = new ArrayList<>(orderColumns.length);
        Arrays.sort(orderColumns, KnifeReportColumnOrder::compareTo);
        for (KnifeReportColumnOrder orderColumn : orderColumns) {
            String fieldName = orderColumn.getFieldName();
            KnifeReportHeaderColumnAnnotation knifeReportHeaderColumnAnnotation = map.get(fieldName);
            Assert.notNull(knifeReportHeaderColumnAnnotation,fieldName+"属性未添加KnifeReportHeaderColumnAnnotation注解");
            KnifeReportHeaderColumn knifeReportHeaderColumn = new KnifeReportHeaderColumn(
                    knifeReportHeaderColumnAnnotation.title(),
                    knifeReportHeaderColumnAnnotation.type(),
                    fieldName
            );
            knifeReportHeaderColumns.add(knifeReportHeaderColumn);
        }
        return knifeReportHeaderColumns;
    }

    @Override
    public List<KnifeReportLineColumn> buildLineColumns(ColumnOrderEnum columnOrderEnum) {
        KnifeReportColumnOrder[] orderColumns = columnOrderEnum.getOrderColumns();
        List<Field> fieldList = KnifeReflectUtil.getAllFieldRecursionWithAnnotation(lineClass, KnifeReportLineColumnAnnotation.class);
        // 转化为Map
        Map<String, KnifeReportLineColumnAnnotation> map = new HashMap<>(fieldList.size());
        fieldList.forEach(field -> {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            map.put(field.getName(), field.getAnnotation(KnifeReportLineColumnAnnotation.class));
        });

        List<KnifeReportLineColumn> knifeReportLineColumns = new ArrayList<>(orderColumns.length);
        Arrays.sort(orderColumns, KnifeReportColumnOrder::compareTo);
        for (int i = 0; i < orderColumns.length; i++) {
            KnifeReportColumnOrder orderColumn = orderColumns[i];
            String fieldName = orderColumn.getFieldName();
            KnifeReportLineColumnAnnotation knifeReportLineColumnAnnotation = map.get(fieldName);
            Assert.notNull(knifeReportLineColumnAnnotation,fieldName+"属性未添加KnifeReportLineColumnAnnotation注解");
            KnifeReportLineColumn knifeReportHeaderColumn = new KnifeReportLineColumn(
                    knifeReportLineColumnAnnotation.title(),
                    i,
                    knifeReportLineColumnAnnotation.align(),
                    knifeReportLineColumnAnnotation.width()
            );
            knifeReportLineColumns.add(knifeReportHeaderColumn);
        }

        return knifeReportLineColumns;
    }
}
